/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package codegen.ui.nbvisual.visual;

import codegen.glsl.GLSLCodeGeneration;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.util.List;
import java.util.Random;
import javax.swing.JComponent;
import org.netbeans.api.visual.action.WidgetAction;
import org.netbeans.api.visual.widget.Widget;
import org.openide.util.ImageUtilities;
import codegen.graphnetwork.model.*;
/**
 *
 * @author cuong.nguyenmanh2
 */
public class CodeGenGraphManager {

    private WidgetAction createAction = new SceneCreateAction();
    private static final Image IMAGE_LIST = ImageUtilities.loadImage("test/resources/list_16.png"); // NOI18N
    private static final Image IMAGE_ITEM = ImageUtilities.loadImage("test/resources/item_16.png"); // NOI18N
    private static int nodeID = 1;
    private static int edgeID = 1;
    private CodeGenGraphScene scene;
    private JComponent view;
    private JComponent satelliteView;
    private boolean addingNodeMode = true;
    private String currentType;
    private GLSLCodeGeneration codeGenResovler;
    Random rand=new Random();
    private class SceneCreateAction extends WidgetAction.Adapter {

        public WidgetAction.State mousePressed(Widget widget, WidgetAction.WidgetMouseEvent event) {
            if (event.getClickCount() == 1) {
                if (event.getButton() == MouseEvent.BUTTON1 || event.getButton() == MouseEvent.BUTTON3) {
                    if (addingNodeMode) {
                        nodeID++;
                        //Node newNode = createEmptyNode();
                        Node newNode = createTypeNode(currentType);
                        Widget nodeWidget = scene.addNode(newNode);

                        nodeWidget.setPreferredLocation(widget.convertLocalToScene(event.getPoint()));
                        createPinsForNode(newNode, 1+rand.nextInt(6));
                        return WidgetAction.State.CONSUMED;
                    }
                }
            }
            return WidgetAction.State.REJECTED;
        }
    }

    public JComponent getView() {
        if (this.view == null) {
            this.view = scene.createView();
        }
        return this.view;
    }

    public JComponent getBirdEyeView() {
        if (this.satelliteView == null) {
            this.satelliteView = scene.createSatelliteView();
        }
        return this.satelliteView;
    }

    public CodeGenGraphScene createScene() {
        this.scene = new CodeGenGraphScene();
        setupActions();
        addSampleNodes();
        return scene;
    }

    public void addSampleNodes() {
        Node varA = createNode(scene, 100, 100, IMAGE_LIST, "VarA", "List", null);
        createPin(scene, varA, "VarA", IMAGE_ITEM, "Input Value1", "Float", true);
        createPin(scene, varA, "VarA", IMAGE_ITEM, "Output Value1", "Float", false);

        Node varB = createNode(scene, 400, 400, IMAGE_LIST, "VarB", "List", null);
        createPin(scene, varB, "VarB", IMAGE_ITEM, "Input Value2", "Float", true);
        createPin(scene, varB, "VarB", IMAGE_ITEM, "Output Value2", "Float", false);

        //createEdge(scene, "start", menu);
        //createEdge2(scene, "varA", "varB");

        //createEdge(scene, "game", game);
        //createEdge(scene, "exit", mobile);

        //createEdge(scene, "ok", menu);
        //createEdge(scene, "cancel", menu);
/*
         CodeGenNodeWidget widget = (CodeGenNodeWidget) scene.findWidget(varA);
         HashMap<String, List<Widget>> categories = new HashMap<String, List<Widget>>();
         categories.put("Input", Arrays.asList(scene.findWidget("Input Value1")));
         categories.put("Output", Arrays.asList(scene.findWidget("Output Value1")));
         widget.sortPins(categories);
         */
    }

    void resovleGLSL() {
        if (this.codeGenResovler == null) {
            codeGenResovler = new GLSLCodeGeneration(scene);
        }
        codeGenResovler.codeGen();


    }

    public GLSLCodeGeneration getCodeGenResovler() {
        return codeGenResovler;
    }

    void setupActions() {
        /*
         scene.getActions().addAction(ActionFactory.createEditAction(new EditProvider() {
         public void edit(Widget widget) {
         scene.layoutScene();
         }
         }));
         */
        scene.getActions().addAction(createAction);
    }

    static Node createNode(CodeGenGraphScene scene, int x, int y, Image image, String name, String type, List<Image> glyphs) {
        //String nodeID = "node" + NBGraphTest.nodeID++;
        Node newNode = new Node(name);
        //Value defaultValue = new Value("Int", "defaultValue", 1);
        CodeGenNodeWidget widget = (CodeGenNodeWidget) scene.addNode(newNode);
        widget.setPreferredLocation(new Point(x, y));
        widget.setNodeProperties(image, name, type, glyphs);
        //scene.addPin(newNode, defaultValue);
        return newNode;
    }
    /*
     static void createPin(CodeGenGraphScene scene, String nodeID, String pinID, Image image, String name, String type) {
     Node parentNode = scene.getNodeById(nodeID);
     createPin(scene, parentNode.getName(), pinID, image, name, type);
     }
     */

    static void createPin(CodeGenGraphScene scene, Node parentNode, String pinID, Image image, String name, String type, boolean isInput) {

        Value newValue = new Value(type, name, 3);
        newValue.isInput = isInput;
        CodeGenPinWidget pinWidget = (CodeGenPinWidget) scene.addPin(parentNode, newValue);

        //pinWidget.setProperties(name, null);


        // uncomment this in case, you would like to allow to move a node by dragging any area of the node (including pins)
//        final Widget nodeWidget = scene.findWidget (nodeID);
//        final WidgetAction originalMoveAction = ActionFactory.createMoveAction ();
//
//        pinWidget.getActions ().addAction (new WidgetAction() {
//
//            public State mouseClicked (Widget widget, WidgetMouseEvent event) {
//                Point point = nodeWidget.convertSceneToLocal (widget.convertLocalToScene (event.getPoint ()));
//                return originalMoveAction.mouseClicked (nodeWidget, new WidgetMouseEvent (event.getEventID (), new MouseEvent (widget.getScene ().getView (), 0, event.getWhen (), event.getModifiersEx (), point.x, point.y, event.getClickCount (), event.isPopupTrigger (), event.getButton ())));
//            }
//
//            public State mousePressed (Widget widget, WidgetMouseEvent event) {
//                Point point = nodeWidget.convertSceneToLocal (widget.convertLocalToScene (event.getPoint ()));
//                return originalMoveAction.mousePressed (nodeWidget, new WidgetMouseEvent (event.getEventID (), new MouseEvent (widget.getScene ().getView (), 0, event.getWhen (), event.getModifiersEx (), point.x, point.y, event.getClickCount (), event.isPopupTrigger (), event.getButton ())));
//            }
//
//            public State mouseReleased (Widget widget, WidgetMouseEvent event) {
//                Point point = nodeWidget.convertSceneToLocal (widget.convertLocalToScene (event.getPoint ()));
//                return originalMoveAction.mouseReleased (nodeWidget, new WidgetMouseEvent (event.getEventID (), new MouseEvent (widget.getScene ().getView (), 0, event.getWhen (), event.getModifiersEx (), point.x, point.y, event.getClickCount (), event.isPopupTrigger (), event.getButton ())));
//            }
//
//            public State mouseEntered (Widget widget, WidgetMouseEvent event) {
//                Point point = nodeWidget.convertSceneToLocal (widget.convertLocalToScene (event.getPoint ()));
//                return originalMoveAction.mouseEntered (nodeWidget, new WidgetMouseEvent (event.getEventID (), new MouseEvent (widget.getScene ().getView (), 0, event.getWhen (), event.getModifiersEx (), point.x, point.y, event.getClickCount (), event.isPopupTrigger (), event.getButton ())));
//            }
//
//            public State mouseExited (Widget widget, WidgetMouseEvent event) {
//                Point point = nodeWidget.convertSceneToLocal (widget.convertLocalToScene (event.getPoint ()));
//                return originalMoveAction.mouseExited (nodeWidget, new WidgetMouseEvent (event.getEventID (), new MouseEvent (widget.getScene ().getView (), 0, event.getWhen (), event.getModifiersEx (), point.x, point.y, event.getClickCount (), event.isPopupTrigger (), event.getButton ())));
//            }
//
//            public State mouseDragged (Widget widget, WidgetMouseEvent event) {
//                Point point = nodeWidget.convertSceneToLocal (widget.convertLocalToScene (event.getPoint ()));
//                return originalMoveAction.mouseDragged (nodeWidget, new WidgetMouseEvent (event.getEventID (), new MouseEvent (widget.getScene ().getView (), 0, event.getWhen (), event.getModifiersEx (), point.x, point.y, event.getClickCount (), event.isPopupTrigger (), event.getButton ())));
//            }
//
//            public State mouseMoved (Widget widget, WidgetMouseEvent event) {
//                Point point = nodeWidget.convertSceneToLocal (widget.convertLocalToScene (event.getPoint ()));
//                return originalMoveAction.mouseMoved (nodeWidget, new WidgetMouseEvent (event.getEventID (), new MouseEvent (widget.getScene ().getView (), 0, event.getWhen (), event.getModifiersEx (), point.x, point.y, event.getClickCount (), event.isPopupTrigger (), event.getButton ())));
//            }
//
//            public State mouseWheelMoved (Widget widget, WidgetMouseWheelEvent event) {
//                Point point = nodeWidget.convertSceneToLocal (widget.convertLocalToScene (event.getPoint ()));
//                return originalMoveAction.mouseWheelMoved (nodeWidget, new WidgetMouseWheelEvent (event.getEventID (), new MouseWheelEvent (widget.getScene ().getView (), 0, event.getWhen (), event.getModifiersEx (), point.x, point.y, event.getClickCount (), event.isPopupTrigger (), event.getScrollType (), event.getScrollAmount (), event.getWheelRotation ())));
//            }
//
//            public State keyTyped (Widget widget, WidgetKeyEvent event) {
//                return originalMoveAction.keyTyped (nodeWidget, event);
//            }
//
//            public State keyPressed (Widget widget, WidgetKeyEvent event) {
//                return originalMoveAction.keyPressed (nodeWidget, event);
//            }
//
//            public State keyReleased (Widget widget, WidgetKeyEvent event) {
//                return originalMoveAction.keyReleased (nodeWidget, event);
//            }
//
//            public State focusGained (Widget widget, WidgetFocusEvent event) {
//                return originalMoveAction.focusGained (nodeWidget, event);
//            }
//
//            public State focusLost (Widget widget, WidgetFocusEvent event) {
//                return originalMoveAction.focusLost (nodeWidget, event);
//            }
//
//            public State dragEnter (Widget widget, WidgetDropTargetDragEvent event) {
//                return originalMoveAction.dragEnter (nodeWidget, event);
//            }
//
//            public State dragOver (Widget widget, WidgetDropTargetDragEvent event) {
//                return originalMoveAction.dragOver (nodeWidget, event);
//            }
//
//            public State dropActionChanged (Widget widget, WidgetDropTargetDragEvent event) {
//                return originalMoveAction.dropActionChanged (nodeWidget, event);
//            }
//
//            public State dragExit (Widget widget, WidgetDropTargetEvent event) {
//                return originalMoveAction.dragExit (nodeWidget, event);
//            }
//
//            public State drop (Widget widget, WidgetDropTargetDropEvent event) {
//                return originalMoveAction.drop (nodeWidget, event);
//            }
//        });
    }

    static void createEdge2(CodeGenGraphScene scene, String sourcePinID, String targetPinID) {
        String edgeIDStr = "edge" + edgeID++;
        Link newEdge = new Link(edgeIDStr);
        scene.addEdge(newEdge);
        Value sourcePin = scene.getPinById(sourcePinID);
        Value targetPin = scene.getPinById(targetPinID);
        scene.setEdgeSource(newEdge, sourcePin);
        scene.setEdgeTarget(newEdge, targetPin);
    }

    private Node createEmptyNode() {
        Node newNode = new Node("new Node" + nodeID);

        return newNode;
    }

    private void createPinsForNode(Node newNode, int num) {
        for (int i = 0; i < num; i++) {
            Value newValue = new Value("Float", "Value" + nodeID + " " + i, 1f);
            if (i % 2 == 1) {
                newValue.isInput = true;
            } else {
                newValue.isInput = false;
            }
            scene.addPin(newNode, newValue);
        }
    }

    private Node createTypeNode(String type) {
        return CodeGenNodeFactory.createTypeNode(type);

    }

    public String getCurrentType() {
        return currentType;
    }

    public void setAddingNodeMode(boolean addingNodeMode) {
        this.addingNodeMode = addingNodeMode;
    }

    public boolean isAddingNodeMode() {
        return addingNodeMode;
    }

    public void setCurrentType(String currentType) {
        this.currentType = currentType;
    }
}
